Q-3: Secondary Storage Permissions OR Telephony API (5 Marks)
Questions​
a) What necessary permissions are required to store data on secondary memory in android? Discuss various methods associated to store data on secondary memory. (5 marks)
OR
b) Write a note on telephony API and its key features. (5 marks)
Answers​
a) Secondary Storage Permissions and Methods​
Required Permissions for Secondary Storage​
1. Manifest Permissions (Before Android 10):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2. Runtime Permissions (Android 6.0+):
// Check and request permissions
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
}
3. Scoped Storage (Android 10+):
- Limited external storage access
- App-specific directories don't require permissions
- MediaStore API for media files
- Storage Access Framework for document access
Permission Handling Code​
public class StoragePermissionHelper {
private static final int REQUEST_CODE_STORAGE = 100;
private Activity activity;
public StoragePermissionHelper(Activity activity) {
this.activity = activity;
}
public boolean hasStoragePermission() {
return ContextCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public void requestStoragePermission() {
ActivityCompat.requestPermissions(activity,
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CODE_STORAGE);
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_CODE_STORAGE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
Toast.makeText(activity, "Storage permission granted", Toast.LENGTH_SHORT).show();
} else {
// Permission denied
Toast.makeText(activity, "Storage permission denied", Toast.LENGTH_SHORT).show();
}
}
}
}
Methods to Store Data on Secondary Memory​
1. External Storage Directories
public class ExternalStorageHelper {
// Get external storage directory
public File getExternalStorageDir() {
return Environment.getExternalStorageDirectory();
}
// Get app-specific external directory (No permission required Android 4.4+)
public File getAppExternalDir(Context context) {
return context.getExternalFilesDir(null);
}
// Get external cache directory
public File getExternalCacheDir(Context context) {
return context.getExternalCacheDir();
}
// Check if external storage is available
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
// Check if external storage is readable
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
}
}
2. File Writing to External Storage
public void writeToExternalStorage(String filename, String data) {
if (isExternalStorageWritable()) {
File file = new File(getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), filename);
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(data.getBytes());
fos.close();
Toast.makeText(this, "File saved to external storage", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Error saving file", Toast.LENGTH_SHORT).show();
}
}
}
// Read from external storage
public String readFromExternalStorage(String filename) {
if (isExternalStorageReadable()) {
File file = new File(getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), filename);
try {
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];
fis.read(buffer);
fis.close();
return new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
3. MediaStore API (For Media Files)
public void saveImageToMediaStore(Bitmap bitmap, String displayName) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, displayName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
}
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try {
OutputStream outputStream = getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.close();
Toast.makeText(this, "Image saved to gallery", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
4. Storage Access Framework (SAF)
// Open document picker
private void openDocumentPicker() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/*");
startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT);
}
// Create document
private void createDocument() {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TITLE, "newfile.txt");
startActivityForResult(intent, REQUEST_CODE_CREATE_DOCUMENT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_CREATE_DOCUMENT && resultCode == RESULT_OK) {
Uri uri = data.getData();
writeToUri(uri, "Hello World!");
}
}
private void writeToUri(Uri uri, String content) {
try {
OutputStream outputStream = getContentResolver().openOutputStream(uri);
outputStream.write(content.getBytes());
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
b) Telephony API and Key Features​
Definition​
Telephony API in Android provides access to telephony-related information and functionality, allowing applications to interact with the device's phone capabilities.
Key Classes​
- TelephonyManager: Main class for telephony operations
- SmsManager: Handle SMS operations
- PhoneStateListener: Monitor phone state changes
- CallLog: Access call history
Required Permissions​
<!-- Basic telephony permissions -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<!-- SMS permissions -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<!-- Call permissions -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<!-- Location for cell info -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Key Features and Implementation​
1. Phone Information
public class TelephonyHelper {
private TelephonyManager telephonyManager;
private Context context;
public TelephonyHelper(Context context) {
this.context = context;
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
// Get device information
@SuppressLint("MissingPermission")
public void getDeviceInfo() {
// Network operator name
String operatorName = telephonyManager.getNetworkOperatorName();
// Device ID (IMEI)
String deviceId = telephonyManager.getDeviceId();
// Phone number
String phoneNumber = telephonyManager.getLine1Number();
// Network type
int networkType = telephonyManager.getNetworkType();
String networkTypeName = getNetworkTypeName(networkType);
// SIM state
int simState = telephonyManager.getSimState();
String simStateName = getSimStateName(simState);
Log.d("TelephonyInfo", "Operator: " + operatorName);
Log.d("TelephonyInfo", "Device ID: " + deviceId);
Log.d("TelephonyInfo", "Phone Number: " + phoneNumber);
Log.d("TelephonyInfo", "Network Type: " + networkTypeName);
Log.d("TelephonyInfo", "SIM State: " + simStateName);
}
private String getNetworkTypeName(int networkType) {
switch (networkType) {
case TelephonyManager.NETWORK_TYPE_GPRS: return "GPRS";
case TelephonyManager.NETWORK_TYPE_EDGE: return "EDGE";
case TelephonyManager.NETWORK_TYPE_UMTS: return "UMTS";
case TelephonyManager.NETWORK_TYPE_HSDPA: return "HSDPA";
case TelephonyManager.NETWORK_TYPE_LTE: return "LTE";
default: return "Unknown";
}
}
private String getSimStateName(int simState) {
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT: return "No SIM";
case TelephonyManager.SIM_STATE_READY: return "SIM Ready";
case TelephonyManager.SIM_STATE_LOCKED: return "SIM Locked";
default: return "Unknown";
}
}
}
2. Phone State Monitoring
public class PhoneStateMonitor extends PhoneStateListener {
private Context context;
public PhoneStateMonitor(Context context) {
this.context = context;
}
@Override
public void onCallStateChanged(int state, String phoneNumber) {
super.onCallStateChanged(state, phoneNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.d("PhoneState", "Phone is idle");
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.d("PhoneState", "Phone is ringing: " + phoneNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d("PhoneState", "Phone is in call");
break;
}
}
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
super.onSignalStrengthsChanged(signalStrength);
Log.d("PhoneState", "Signal strength changed: " + signalStrength.toString());
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
super.onDataConnectionStateChanged(state, networkType);
switch (state) {
case TelephonyManager.DATA_CONNECTED:
Log.d("PhoneState", "Data connected");
break;
case TelephonyManager.DATA_DISCONNECTED:
Log.d("PhoneState", "Data disconnected");
break;
}
}
}
// Register listener in activity
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
PhoneStateMonitor phoneStateMonitor = new PhoneStateMonitor(this);
telephonyManager.listen(phoneStateMonitor, PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
3. SMS Operations
public class SMSHelper {
// Send SMS
public void sendSMS(String phoneNumber, String message) {
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNumber, null, message, null, null);
Toast.makeText(context, "SMS sent successfully", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(context, "SMS failed to send", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
// Send long SMS (multipart)
public void sendLongSMS(String phoneNumber, String message) {
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> parts = smsManager.divideMessage(message);
smsManager.sendMultipartTextMessage(phoneNumber, null, parts, null, null);
}
// Read SMS from inbox
@SuppressLint("Range")
public List<SMS> readSMS() {
List<SMS> smsList = new ArrayList<>();
Uri smsUri = Uri.parse("content://sms/inbox");
Cursor cursor = context.getContentResolver().query(smsUri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
do {
String address = cursor.getString(cursor.getColumnIndex("address"));
String body = cursor.getString(cursor.getColumnIndex("body"));
long date = cursor.getLong(cursor.getColumnIndex("date"));
SMS sms = new SMS(address, body, date);
smsList.add(sms);
} while (cursor.moveToNext());
cursor.close();
}
return smsList;
}
}
4. Call Operations
public class CallHelper {
// Make phone call
public void makeCall(Context context, String phoneNumber) {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + phoneNumber));
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE)
== PackageManager.PERMISSION_GRANTED) {
context.startActivity(callIntent);
}
}
// Open dialer
public void openDialer(Context context, String phoneNumber) {
Intent dialIntent = new Intent(Intent.ACTION_DIAL);
dialIntent.setData(Uri.parse("tel:" + phoneNumber));
context.startActivity(dialIntent);
}
// Read call log
@SuppressLint("Range")
public List<CallLogEntry> readCallLog(Context context) {
List<CallLogEntry> callLog = new ArrayList<>();
Cursor cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI, null, null, null,
CallLog.Calls.DATE + " DESC");
if (cursor != null && cursor.moveToFirst()) {
do {
String number = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
String name = cursor.getString(cursor.getColumnIndex(CallLog.Calls.CACHED_NAME));
int type = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
long date = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE));
int duration = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.DURATION));
CallLogEntry entry = new CallLogEntry(number, name, type, date, duration);
callLog.add(entry);
} while (cursor.moveToNext());
cursor.close();
}
return callLog;
}
}
Applications of Telephony API​
- Call Management Apps: Call blocking, call recording
- SMS Applications: Custom SMS clients, SMS backup
- Network Monitoring: Signal strength monitoring, network analysis
- Security Apps: Device tracking, anti-theft features
- Communication Apps: VoIP applications, messaging platforms
- Business Apps: Customer relationship management, sales tracking